﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Affirma.ThreeSharp.Wrapper;
using System.Xml;
using System.IO;
using Dokan;

namespace CloudDrive.S3
{
    public class S3Proxy
    {
        private IThreeSharpWrapper _ThreeSharpWrapper;
        private string _BucketName;
        private IList<string> _lazyFiles = null;
        private object _Locker = new object();
        public S3Proxy(IThreeSharpWrapper threeSharpWrapper, string bucketName)
        {
            _BucketName = bucketName;
            _ThreeSharpWrapper = threeSharpWrapper;
        }
        private IList<string> _Files
        {
            get 
            {
                lock (_Locker)
                {
                    if (_lazyFiles == null)
                    {
                        string xmlResponse = _ThreeSharpWrapper.ListBucket(_BucketName);
                        XmlDocument xmlDoc = new XmlDocument();
                        xmlDoc.LoadXml(xmlResponse);
                        var documentElement = xmlDoc.DocumentElement;
                        XmlNamespaceManager nsManager = new XmlNamespaceManager(xmlDoc.NameTable);
                        nsManager.AddNamespace("x", documentElement.NamespaceURI);                        
                        var nav = documentElement.SelectNodes("/x:ListBucketResult/x:Contents/x:Key", nsManager);
                        _lazyFiles = new StringList(StringComparer.CurrentCultureIgnoreCase);
                        foreach (XmlNode node in nav)
                            _lazyFiles.Add(node.InnerText);
                    }
                }
                return _lazyFiles;
            }
        }

        private string CreateTemporaryFile()
        {
            string tempFile = Path.GetTempFileName();
            var stream = File.Create(tempFile);
            stream.Close();
            return tempFile;
        }
        public FileObject CreateFile(string fileName, bool overWrite)
        {
            if (!overWrite && FileExists(fileName))
                throw new IOException("File " + fileName + " exists");
            string tempPath = CreateTemporaryFile();
            FileObject file = new FileObject(fileName, tempPath);
            _Files.Add(fileName);
            _ThreeSharpWrapper.AddFileObject(_BucketName, fileName, tempPath);
            return file;
        }
        public void CreateDirectory(string filename, bool overwrite)
        {
            if (!overwrite && FileExists(filename))
                throw new IOException("Directory " + filename + " exists");
            if (filename == "\\")
                return;
            _Files.Add(filename);
            _ThreeSharpWrapper.AddEmptyFolder(_BucketName, filename);
        }
        public bool FileExists(string filename)
        {
            if (filename == "\\")
                return true;
            return _Files.Contains(filename);
        }
        public FileObject OpenFile(string filename)
        {
            if (!_Files.Contains(filename))
                throw new FileNotFoundException();
            string tempPath = CreateTemporaryFile();
            _ThreeSharpWrapper.GetFileObject(_BucketName, filename, tempPath);
            return new FileObject(filename, tempPath);
        }
        public FileObject Truncate(string filename)
        {
            var file = OpenFile(filename);
            file.Truncate();
            return file;
        }
        public FileInformation GetDirectoryInfo(string filename)
        {
            FileInformation info = new FileInformation();
            info.FileName = filename;
            return info;
        }
        public FileInformation GetFileInfo(string filename)
        {
            FileInformation info = new FileInformation();
            info.FileName = filename;
            return info;
        }
        public IEnumerable<FileInformation> FindFiles(string filename)
        {
            var filesWithoutPrefix = _Files.Where(x => x.StartsWith(filename)).Select(x => x.Substring(filename.Length));
            var filesInDirectory = filesWithoutPrefix.Where(x => !x.Contains("\\") || x.IndexOf("\\") == x.Length - 1);
            List<FileInformation> files = new List<FileInformation>();
            foreach (var file in filesInDirectory)
            {
                files.Add(new FileInformation()
                {
                    Attributes = file.EndsWith("\\") ? FileAttributes.Directory : FileAttributes.Normal,
                    FileName = file
                });
            }
            return files;
        }
        public void DeleteFile(string filename)
        {
            _ThreeSharpWrapper.DeleteObject(_BucketName, filename);
            _Files.Remove(filename);
        }
    }
}
